/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package digitaldreamers.libraries.games.servers.networkmanagement.abstracts;

import java.util.ArrayList;

/**
 * This class is used to handle packets from client.
 *
 * @author DaoLe
 */
abstract public class AbPacketHandler implements Runnable {
    
    private static final String MESSAGE__THREAD_ENDED = "%s ended";
    private static final String PACKET_HANDLER_THREAD_NAME = "Packet handling thread";
    
    private ArrayList<byte[]> mDataList;
    private Thread mHandlePacketThread;
    private volatile boolean mIsRunning;
    protected IConnectionHandler mConnectionHandler;
    
    public void setConnectionHandler(IConnectionHandler pConnectionHandler) {
        mConnectionHandler = pConnectionHandler;
    }
    
    /**
     * Create a new instance.
     */
    public AbPacketHandler() {
        this(null);
    }
    
    /**
     * Create a new instance.
     *
     * @param pConnectionHandler The ConnectionHandler that uses this instance.
     */
    public AbPacketHandler(IConnectionHandler pConnectionHandler) {
        this.mConnectionHandler = pConnectionHandler;
        mDataList = new ArrayList<>();
        mIsRunning = false;
    }
    
    /**
     * Add a new packet to the packet list.
     *
     * @param pData The packet pData.
     */
    public synchronized void addPacket(byte[] pData) {
        mDataList.add(pData);
    }

    /**
     * Get a packet from the list to handle.
     *
     * @param pIndex The index of the packet.
     * @return The packet data.
     */
    private synchronized byte[] removePacket(int pIndex) {
        return mDataList.remove(pIndex);
    }

    /**
     * Main process.
     */
    @Override
    public void run() {
        while (mIsRunning) {
            if (mDataList.size() > 0) {
                byte[] data = removePacket(0);
                try {
                    handlePacket(data);
                } catch (Exception ex) {
                    mConnectionHandler.showMessage(ex.getMessage());
                    mConnectionHandler.fireConnectionErrorEvent();
                }
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                mConnectionHandler.showMessage(ex.getMessage());
            }
        }
        System.out.println(String.format(MESSAGE__THREAD_ENDED, PACKET_HANDLER_THREAD_NAME));
    }

    public synchronized  void start() {
        if (!mIsRunning) {
            mIsRunning = true;
            mHandlePacketThread = new Thread(this);
            mHandlePacketThread.start();
        }
    }
    
    /**
     * Stop the packet handling thread.
     * @throws InterruptedException Something wrong happened.
     */
    public synchronized void stop() throws InterruptedException {
        try {
            if (mIsRunning) {
                mIsRunning = false;
                mHandlePacketThread.join();
            }
        } catch (InterruptedException ex) {
            throw ex;
        }
    }

    /**
     * Handle the packet. Should implement this method.
     *
     * @param pData The packet data.
     * @throws Exception Exception that occurred while handling data.
     */
    abstract protected void handlePacket(byte[] pData) throws Exception;
}
